import base64
import uuid
from io import BytesIO

import requests
import tos
import uvicorn
import websockets
from fastapi import FastAPI, Request, HTTPException, UploadFile, Depends, File
from fastapi import WebSocket, WebSocketDisconnect
import asyncio
from typing import Optional, List
from pydantic import BaseModel
from sse_starlette import EventSourceResponse
import gzip
import json

from asr.streaming_asr_demo import (
    AsrWsClient,
    generate_header,
    generate_audio_default_header,
    generate_last_audio_default_header,
    CLIENT_AUDIO_ONLY_REQUEST,
    NEG_SEQUENCE,
    parse_response,
    AudioType,
)
from config import OSS_ACCESS_KEY_ID, OSS_ACCESS_KEY_SECRET, OOS_REGION, OSS_ENDPOINT, OSS_BUCKET, TTS_APPID, \
    TTS_ACCESS_TOKEN, TTS_CLUSTER, TTS_VOICE_TYPE, TTS_API_URL, ASR_CLUSTER, ASR_TOKEN, ASR_APPID, ASR_AUDIO_FORMAT
from graph.interview_chat_service import generate_stream
from graph.interview_init_service import generate_summary, generate_questions
from graph.interview_result_service import interview_eval_result
from logger.log_config import logger
from mapper.thread import create_thread
from utils.parse_utils import fetch_and_parse_file_content
from starlette.responses import JSONResponse

app = FastAPI()


class InitRequest(BaseModel):
    job_description: str
    resume_url: str


@app.post("/initialize")
async def initialize(request: InitRequest):
    job_description = request.job_description
    resume_url = request.resume_url
    try:
        # 使用 file_parser_util 处理本地的文件
        resume_text = fetch_and_parse_file_content(resume_url)
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Failed to parse the resume: {e}")
    try:
        # 使用并行异步处理，生成两个核心任务
        # 并行任务包含 (1) 生成问题 和 (2) 生成个人信息摘要
        summary_task = generate_summary(job_description, resume_text)
        questions_task = generate_questions(job_description, resume_text)

        # 使用 asyncio.gather 并行执行任务，确保两个 LLM 节点同时运行
        personal_summary, question_res = await asyncio.gather(summary_task, questions_task)
        questions = question_res.get('questions', '')
        company = question_res.get('company', '')
        job_position = question_res.get('job_position', '')

        # 在实际场景中，可以将结果存储到数据库中，供后续面试流程使用
        logger.info(f"个人信息摘要（Personal Summary）:{personal_summary}")
        logger.info(f"待提问问题（Questions）:{questions}")
        thread = create_thread(resume_url=resume_url, job_description=job_description,
                               resume_summary=personal_summary, questions=questions, position=job_position,
                               company=company)
        return JSONResponse(status_code=200, content={"id": thread.id})

    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Initialization failed: {str(e)}")


class Message(BaseModel):
    role: str  # 消息的角色，比如 "user" 或 "assistant"
    content: str  # 消息的具体内容


class ThreadRequest(BaseModel):
    thread_id: int  # 必须提供的线程 ID
    messages: Optional[List[Message]] = None  # 可选的上下文消息列表


@app.post("/chat/sse")
def generate_request_id(req: ThreadRequest):
    logger.info(f'线程id为:{req.thread_id}')
    logger.info(f'消息为:{req.messages}')
    incoming_message = ''
    if req.messages and len(req.messages) > 0:
        incoming_message = req.messages[-1].content
    stream_generator = generate_stream(req.thread_id, incoming_message)
    return EventSourceResponse(stream_generator, media_type="text/event-stream")


class ThreadInfo(BaseModel):
    thread_id: int  # 必须提供的线程 ID


@app.post("/eval")
def interview_eval(req: ThreadInfo):
    logger.info(f"面试评价请求thread_id:{req.thread_id}")
    res = interview_eval_result(req.thread_id)
    return JSONResponse(status_code=200, content=res)



# TOS（字节跳动对象存储）基础配置
ak = OSS_ACCESS_KEY_ID
sk = OSS_ACCESS_KEY_SECRET
endpoint = OSS_ENDPOINT  # 对象存储服务的 Endpoint
region = OOS_REGION
bucket_name = OSS_BUCKET


# 获取请求头中的 Authorization 值
def get_auth_value(request: Request) -> Optional[str]:
    auth = request.headers.get("Authorization")
    return auth


@app.post("/upload")
def upload_to_tos(
        file: UploadFile = File(...),
        access_key_id: str = Depends(get_auth_value)
):
    """
    上传文件到 TOS，并返回文件的公开访问 URL
    """
    if not access_key_id:
        raise HTTPException(status_code=401, detail="Authorization header required")

    if access_key_id != ak:  # 你可以添加更复杂的验证逻辑
        raise HTTPException(status_code=403, detail="Invalid access key")

    try:
        # 初始化客户端
        client = tos.TosClientV2(ak, sk, endpoint, region)

        # 文件目标路径（例如：uploads/filename）
        object_key = f"uploads/{file.filename}"

        # 上传文件到 TOS
        client.put_object(bucket_name, object_key, content=file.file)

        # 构建文件的公开 URL
        upload_url = f"https://{bucket_name}.{endpoint}/{object_key}"

        return JSONResponse(content={"url": upload_url})

    except tos.exceptions.TosClientError as e:
        return JSONResponse(
            content={"error": f"TOS Client Error: {e.message}, cause: {e.cause}"},
            status_code=500
        )
    except tos.exceptions.TosServerError as e:
        return JSONResponse(
            content={
                "error": f"TOS Server Error: {e.message}, code: {e.code}, request_id: {e.request_id}"
            },
            status_code=500
        )
    except Exception as e:
        return JSONResponse(content={"error": str(e)}, status_code=500)


# TTS 配置
tts_appid = TTS_APPID
tts_access_token = TTS_ACCESS_TOKEN  # 替换为实际 access_token
tts_cluster = TTS_CLUSTER
tts_voice_type = TTS_VOICE_TYPE
tts_api_url = TTS_API_URL


# 定义数据模型
class TTSRequest(BaseModel):
    text: str  # 输入文本
    speed_ratio: float = 1.0  # 语速，默认 1.0
    volume_ratio: float = 1.0  # 音量，默认 1.0
    pitch_ratio: float = 1.0  # 音调，默认 1.0


@app.post("/tts")
def tts(request: TTSRequest):
    logger.info(f'tts请求入参:\n{request}')
    """
    接受文本并调用 TTS 服务，返回合成语音的 Base64 数据
    """
    # 构造 TTS 请求数据
    request_json = {
        "app": {
            "appid": tts_appid,
            "token": "access_token",
            "cluster": tts_cluster
        },
        "user": {
            "uid": str(uuid.uuid4())  # 随机生成唯一用户 ID
        },
        "audio": {
            "voice_type": tts_voice_type,
            "encoding": "mp3",
            "speed_ratio": request.speed_ratio,
            "volume_ratio": request.volume_ratio,
            "pitch_ratio": request.pitch_ratio,
        },
        "request": {
            "reqid": str(uuid.uuid4()),
            "text": request.text,
            "text_type": "plain",
            "operation": "query",
            "with_frontend": 1,
            "frontend_type": "unitTson"
        }
    }

    try:
        # 调用 TTS API
        header = {"Authorization": f"Bearer;{tts_access_token}"}
        response = requests.post(tts_api_url, json=request_json, headers=header)
        response_data = response.json()

        # 检查响应体
        if not response.ok or "data" not in response_data:
            raise HTTPException(status_code=500, detail=f"TTS generation failed: {response_data}")

        # 返回 Base64 音频数据
        return response_data

    except requests.exceptions.RequestException as e:
        # 捕获 HTTP 请求异常
        raise HTTPException(status_code=500, detail=f"Failed to call TTS API: {str(e)}")
    except Exception as e:
        # 捕获其他异常
        raise HTTPException(status_code=500, detail=f"An error occurred: {str(e)}")


audio_format = "wav"
appid = "4947800657"
token = "_A-BqRPuM-9N_r4xGpzIscnJVUlM8v_5"
cluster = "volcengine_streaming_common"


@app.websocket("/asr/realtime")
async def websocket_asr(websocket: WebSocket):
    """
    实时 ASR WebSocket 接口：接受音频流，实时返回语音识别结果
    """
    await websocket.accept()
    logger.info("🔌 WebSocket 连接已建立，等待前端数据流。")

    try:
        # 初始化 ASR 客户端配置（不会真正发送 audio_path，因为是实时流式处理）
        asr_client = AsrWsClient(
            audio_path=None,  # 实时处理所以没有直接的文件路径
            cluster=cluster,
            appid=appid,
            token=token,
            format=audio_format,
            audio_type=AudioType.LOCAL,
        )
        logger.info("🔧 已初始化 ASR 客户端配置。")

        buffer = bytearray()  # 用于临时缓冲接收的音频流片段
        is_streaming = True

        # 构建 full client request，并序列化和压缩
        reqid = str(uuid.uuid4())
        config_request = asr_client.construct_request(reqid)
        payload_bytes = gzip.compress(json.dumps(config_request).encode("utf-8"))
        full_client_request = bytearray(generate_header())  # 使用独立的工具函数
        full_client_request.extend(len(payload_bytes).to_bytes(4, "big"))
        full_client_request.extend(payload_bytes)

        # 与 ASR WebSocket 服务建立连接
        async with websockets.connect(asr_client.ws_url, additional_headers=asr_client.token_auth()) as asr_ws:
            logger.info("🌐 与 ASR WebSocket 服务建立连接成功。")

            # 发送初始化请求到 ASR 服务端
            await asr_ws.send(full_client_request)
            logger.info("📤 初始化请求已发送到 ASR 服务。")

            # 接收 ASR 服务的初始化响应
            init_response = await asr_ws.recv()
            init_result = parse_response(init_response)
            logger.info(f"📥 收到 ASR 服务初始响应：{init_result}")
            if "payload_msg" in init_result and init_result["payload_msg"].get("code") != 1000:
                error_msg = init_result.get("payload_msg")
                logger.error(f"❌ ASR 服务初始化失败：{error_msg}")
                await websocket.send_json({"success": False, "error": error_msg})
                return

            while is_streaming:
                # 从前端接收音频片段
                message = await websocket.receive_json()
                # data = await websocket.receive_bytes()
                message_type = message["type"]
                # data = message["data"]
                base64_data = message["data"]
                logger.info(f"📥 收到前端 Base64 数据片段，大小：{len(base64_data)} 字节。")

                # 解码 Base64 数据
                data = base64.b64decode(base64_data)
                logger.info(f"📥 解码完成，字节大小：{len(data)} 字节。")
                # logger.info(f"📥 收到前端音频片段，大小：{len(data)} 字节。")

                # 如果前端发送空数据或者特殊结束标志，标识音频结束
                # if message_type == "end":
                #     logger.info("🛑 检测到前端结束信号，停止接收数据流。")
                #     is_streaming = False
                #     break

                # 将音频片段发送给 ASR 服务
                payload_bytes = gzip.compress(data)
                if message_type == "end":
                    # 发送结束信号（最后一条音频片段）
                    audio_request = bytearray(
                        generate_last_audio_default_header()
                    )
                else:
                    audio_request = bytearray(generate_audio_default_header())
                audio_request.extend(len(payload_bytes).to_bytes(4, "big"))
                audio_request.extend(payload_bytes)
                await asr_ws.send(audio_request)
                logger.info(f"📤 将音频片段发送到 ASR 服务，大小：{len(payload_bytes)} 字节。")

                # 接收并解析 ASR 服务的返回结果
                asr_response = await asr_ws.recv()
                result = parse_response(asr_response)
                logger.info(f"📥 从 ASR 服务收到识别结果：{result}")

                # 如果服务器返回有效结果，实时发送到前端
                if "payload_msg" in result:
                    logger.info(f"✅ 实时识别结果：{result}")
                    await websocket.send_json(result)
                else:
                    logger.error("⚠️ ASR 服务返回的结果无效或为空。")
                    await websocket.send_json({"success": False, "error": "No valid result from ASR server"})
                if message_type == "end":
                    logger.info("🛑 检测到前端结束信号，停止接收数据流。")
                    is_streaming = False
                    break
            # # 发送结束信号（最后一条音频片段）
            # last_audio_request = bytearray(
            #     generate_last_audio_default_header()
            # )  # 使用 NEG_SEQUENCE 标志
            # last_audio_request.extend(b"\x00\x00\x00\x00")  # 空的 payload
            # await asr_ws.send(last_audio_request)
            # logger.info("📤 已发送结束信号到 ASR 服务。")
            #
            # # 接收最终返回结果
            # final_response = await asr_ws.recv()
            # final_result = parse_response(final_response)
            # logger.info(f"📥 收到 ASR 服务的最终识别结果：{final_result}")
            # if "payload_msg" in final_result:
            #     logger.info(f"✅ 最终识别结果：{final_result}")
            #     await websocket.send_json(final_result)

    except Exception as e:
        # 捕获异常即时告知前端，同时记录日志和关闭 WebSocket
        error_message = f"❌ 服务端发生错误：{str(e)}"
        logger.error(error_message)
        await websocket.send_json({"success": False, "error": error_message})
        await websocket.close()

    logger.info("🔒 WebSocket 连接已关闭。")


if __name__ == '__main__':
    uvicorn.run(app, host='0.0.0.0', port=9000)
